#pragma once

#include "mp3types.h"
#include "OutputBuffer.h"

// A class for the synthesis filter bank:
// This class does a fast downsampling from 32, 44.1 or 48 kHz to 8 kHz, if ULAW is defined.
// Frequencies above 4 kHz are removed by ignoring higher subbands.
class CSynthesisFilter
{
	static const real d[512];
	real v1[512], v2[512];
	real *actual_v;				// v1 or v2
	uint32 actual_write_pos;	// 0-15

	real samples[32];			// 32 new subband samples

	uint32 channel;
	real scalefactor;

	void compute_new_v();
	void compute_pcm_samples(COutputBuffer& buffer);

// Clips the pcm sample so it will fit in 16 bits
#ifdef TRUNC_ROUNDING
	int16 clip(real sample)
	{
		return ((sample > 32767.0f) ? (int16) 32767 : ((sample < -32768.0f) ? (int16) -32768 :
				((sample < 0.0f) ? -((int16) (-sample + 0.5f)) : (int16) ( sample + 0.5f))));
	}
#else
	int16 clip(real sample)
	{
#ifdef FIXED_POINT
		return ((sample > 32767.0f) ? 32767 : ((sample < -32768.0f) ? -32768 : sample.getShort()));
#else
		return ((sample > 32767.0f) ? 32767 : ((sample < -32768.0f) ? -32768 : (int16)sample));
#endif
	}
#endif

public:
	// the scalefactor scales the calculated float pcm samples to short values
	// (raw pcm samples are in [-1.0, 1.0], if no violations occur)
	CSynthesisFilter(uint32 channelnumber, real factor = 32768.0);

	void input_sample(real sample, uint32 subbandnumber) { samples[subbandnumber] = sample; };
	// calculate 32 PCM samples and put the into the Obuffer-object
	void calculate_pcm_samples(COutputBuffer& buffer);
	// reset the synthesis filter
	void reset();
};

inline CSynthesisFilter::CSynthesisFilter(uint32 _channel,real factor) : channel(_channel), scalefactor(factor)
{
  reset();
};

inline void CSynthesisFilter::reset()
{
	real *floatp, *floatp2;

	// initialize v1[] and v2[]:
	for (floatp = v1 + 512, floatp2 = v2 + 512; floatp > v1; )
		*--floatp = *--floatp2 = 0.0;

	// initialize samples[]:
	for (floatp = samples + 32; floatp > samples; )
		*--floatp = 0.0;

	actual_v = v1;
	actual_write_pos = 15;
}

inline void CSynthesisFilter::calculate_pcm_samples(COutputBuffer& buffer)
{
	compute_new_v();
	compute_pcm_samples(buffer);

	actual_write_pos = (actual_write_pos + 1) & 0xf;
	actual_v = (actual_v == v1) ? v2 : v1;

	// initialize samples[]:
	for (real *floatp = samples + 32; floatp > samples; )
		*--floatp = 0.0f;
};
